#ifndef __PHYSICS__WORLD__INCLUDED__HH__
#define __PHYSICS__WORLD__INCLUDED__HH__

#include <Newton.h>
#include <Ogre.h>
#include "LitPhysicsPrereqs.h"
#include "LitPhysicsBody.h"
#include "LitPhysicsShapes.h"
#include "LitPhysicsDebug.h"

#include <boost\bind.hpp>
#include <boost\function.hpp>

namespace Lit
{
	namespace Physics
	{
		class LIT_API World
		{
			Lit::Real mFrameTime;
 
			_WorldPtr mWorld;
			Lit::AABB mDimensions;

			void				_resetBodyCallback( Body * );
			CollisionShape *	_createCollision(Lit::Entity * ent, ShapeType type, int shapeId, const Lit::Vec3 &initial_pos, const Lit::Quat& initial_orient );
			std::string			mName;
			Debugger	*		mDebug;
		public:
			typedef boost::function<void( Body * )> BodyIteratorType;

			World( const std::string &name, PlatformOptimisation optimis = PO_NONE, SolverModel solver = SM_ITERATIVE_SIMPLE, const Lit::AABB& dimensions = Lit::AABB::BOX_INFINITE );
			~World( );
		
			Debugger*	getDebugger(){ return mDebug; }
			const Debugger*	getDebugger() const{ return mDebug; }

			BodyIterator getIterator();
			BodyConstIterator getConstIterator() const;

			const std::string &getName() const{ return mName; }

			Body*		getFirstBody();
			const Body* getFirstBody() const;
			Body*		getNextBody( const Body * body );
			const Body*	getNextBody( const Body * body ) const;

			void		forEachBodyDo( BodyIteratorType itor );
			void		resetWorld( );

			void		setPlatformOptimisation( PlatformOptimisation optimis );
			void		setSolverModel( SolverModel model );

			void		clear();

			void		_updateSubRoutine( float dt );
			void		update( float dt );

			void		setSize( const Lit::Vec3 &size );
			void		setCorners( const Lit::Vec3 &minimum, const Lit::Vec3& maximum );
			void		setDimensions( const Lit::AABB& box );
			Lit::AABB	dimensions() const;

			size_t		bodyCount() const;
			NewtonWorld*	getWorld();
			const NewtonWorld* getWorld() const;

			Body* createBody( float mass, Lit::Entity * ent, ShapeType type = ST_BOX, int shapeId=0, const Lit::Vec3 &initial_pos = Lit::Vec3::ZERO, const Lit::Quat& initial_orient = Lit::Quat::IDENTITY );
			Body* createStaticBody( Lit::Entity * ent, ShapeType type=ST_BOX, int shapeId=0, const Lit::Vec3 &initial_pos = Lit::Vec3::ZERO, const Lit::Quat& initial_orient = Lit::Quat::IDENTITY );
			void destroyBody( BodyPtr b );


			static void BodyDestructorCallback( const NewtonBody * b );
			static void BodyTorqueForceCallback( const NewtonBody * b, float timestep, int threadIndex );
			static void BodyTransformCallback( const NewtonBody * b, const float * matrix, int threadIndex );
		};
		typedef Lit::RefPtr<World> WorldPtr;
	};
};

#endif